package main

import (
	"fmt"
	"github.com/gogf/gf/util/gconv"
	"github.com/golang/protobuf/proto"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	tree "gorm_transaction/api/tree/v1" // Import the generated protobuf package
	"io/ioutil"
	"log"
)

/*
在上面的代码中，我们修改了递归函数findAllChildren，
使其从指定节点开始找到所有子孙节点，并将它们构建成protobuf消息的形式。
注意，我们通过Where方法从数据库中获取所有子节点，
并且在递归过程中，将每个子节点添加到父节点的Children字段中。

请注意，您可以通过修改targetID变量来指定要查找其子孙节点的节点ID。
然后，重新运行程序，它将查找指定节点的所有子节点和子孙节点，
并将其保存到data.pb文件中。
*/

// TreeNode represents the structure of your database table
type TreeNode struct {
	ID       int64 `gorm:"primaryKey"`
	ParentID int64
}

// Recursive function to find all children of a node
func findAllChildren(node *TreeNode, protobufNode *tree.TreeNode, db *gorm.DB) {
	var children []TreeNode
	db.Where("parent_id = ?", node.ID).Find(&children)

	for _, child := range children {
		protobufChild := &tree.TreeNode{
			Id:       child.ID,
			ParentId: child.ParentID,
		}
		protobufNode.Children = append(protobufNode.Children, protobufChild)
		findAllChildren(&child, protobufChild, db)
	}
}

func main() {
	// Connect to the database
	db, err := gorm.Open(sqlite.Open("./tests/tree_nodes_find/tree.db"), &gorm.Config{})
	if err != nil {
		log.Fatalf("Error connecting to the database: %v", err)
	}

	// Migrate the table if needed
	if err := db.AutoMigrate(&TreeNode{}); err != nil {
		log.Fatalf("Error migrating table: %v", err)
	}

	// Notice 数据库有数据的话就不用 insert 了~
	// Insert some sample data into the database (You can replace this with your actual data retrieval logic)
	//db.Create(&TreeNode{ID: 1, ParentID: 0})
	//db.Create(&TreeNode{ID: 2, ParentID: 1})
	//db.Create(&TreeNode{ID: 3, ParentID: 1})
	//db.Create(&TreeNode{ID: 4, ParentID: 2})
	//db.Create(&TreeNode{ID: 5, ParentID: 2})
	//db.Create(&TreeNode{ID: 6, ParentID: 3})

	// Query the specified node from the database (change the ID to the one you want to find its children)
	targetID := int64(1)
	var targetNode TreeNode
	if err := db.Where("id = ?", targetID).First(&targetNode).Error; err != nil {
		log.Fatalf("Error querying target node: %v", err)
	}

	// Convert the target node to a protobuf message
	protobufTargetNode := &tree.TreeNode{
		Id:       targetNode.ID,
		ParentId: targetNode.ParentID,
	}

	// Recursively find all the children of the target node
	findAllChildren(&targetNode, protobufTargetNode, db)

	fmt.Println("protobufTargetNode: ", gconv.String(protobufTargetNode))

	// Serialize the protobuf target node to a binary format
	data, err := proto.Marshal(protobufTargetNode)
	if err != nil {
		log.Fatalf("Error marshalling data: %v", err)
	}

	fmt.Println("data: ", gconv.String(data))

	// Save the serialized data to a file
	err = ioutil.WriteFile("./tests/tree_nodes_find/data.pb", data, 0644)
	if err != nil {
		log.Fatalf("Error saving data to file: %v", err)
	}

	fmt.Println("Data saved to data.pb successfully!")
}
